#import pythoncom
from PIL import Image
from selenium import webdriver
from selenium.common.exceptions import NoSuchElementException
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.webdriver import ActionChains
import time
import os
from io import BytesIO
#import sys
import subprocess
#from pathlib import Path as pathdir
#from win32com.client import Dispatch
import psutil
import zipfile
import requests
import base64
import re

import threading
#import xlrd
#from xlutils.copy import copy as copywook
#from concurrent.futures import ThreadPoolExecutor,wait as waitwith
#from concurrent.futures import ALL_COMPLETED,FIRST_COMPLETED,FIRST_EXCEPTION
#import winreg

import fateadm_api


from config import setting



class workbok(threading.Thread):
    def __init__(self,call,run_list,category,webshow,mid,logsing,worksing):
        threading.Thread.__init__(self)
        self.daemon    = True
        self.call      = call
        self.run_list  = run_list
        self.mid       = mid
        self.worksing  = worksing
        self.logsing   = logsing
        self.webshow   = webshow
        self.category  = category
        self.chrome    = WorkerThread(self.logsing,self.worksing,self.mid,self.webshow,self.category)

    def run(self):
        runlist = ["登录","改密"]
        for i in self.run_list:
            data = self.call(i)
            self.logsing.emit("开始运行 || 线程id " + self.mid + " 任务序号 " + str(i+1) + " 详细信息" + str(data))
            try:
                ret = self.chrome.login(True,i,data[0],data[1],data[2])
            except Exception as e:
                self.logsing.emit(str(e.args))
                break
            else:
                if not ret:
                    self.worksing.emit({"type":"successful","id":i,"code":"完成","category":runlist[self.category]})
                else:
                    self.worksing.emit({"type":"failure","id":i,"code":"失败","category":runlist[self.category],"msg":ret})
        self.chrome.myquit()
        self.logsing.emit("线程结束" + self.mid)
        self.worksing.emit({"type":"button","id":self.mid})


class WorkerThread(object):
    def __init__(self,logsing,worksing,mid,webshow,category):
        self.mid               = mid
        self.logsing           = logsing
        self.worksing          = worksing
        self.category          = category
        option                 = webdriver.ChromeOptions()
        option.binary_location = setting.chrome_path
        if webshow:
            option.add_argument('headless')
        self.driver = webdriver.Chrome(executable_path=setting.chromedriver,chrome_options=option)

    def WebDir(self,ysu,xpath,times):
        try:
            WebDriverWait(self.driver,times).until(EC.visibility_of_element_located((ysu,xpath)))
            return True
        except:
            return False

    def update_action(self,xpath_,elenment):
        while True:
            try:
                self.WebDir(By.XPATH, xpath_,2)
                self.driver.find_element_by_xpath(xpath_).click()
                break
            except Exception as e:
                #logeer(str(e),s=True)
                ActionChains(self.driver).move_to_element(elenment).perform()

    def image_str(self,idclass):
        png64 = self.driver.get_screenshot_as_base64()
        png64 = base64.b64decode(png64)
        page_snap_obj = Image.open(BytesIO(png64))
        img = self.driver.find_element_by_css_selector(idclass)
        imgxy = img.location
        right = imgxy['x'] + img.size['width']
        bottom = imgxy['y'] + img.size['height']
        image_obj = page_snap_obj.crop((imgxy['x'], imgxy['y'], right, bottom))
        if not os.path.exists("files"):
            os.mkdir("files")
        file = "files" + "\\" + str(time.time()).replace(".","") + ".png"
        image_obj.save(file)
        return file

    def myquit(self,v=True):
        # self.driver.execute_script("window.open('{0}', '_blank');".format(url))
        if v:
            self.driver.quit()
        else:
            while len(self.driver.window_handles) > 1:
                self.driver.switch_to.window(self.driver.window_handles[0])
                self.driver.close()
            #print("cookies",self.driver.get_cookies())
            self.driver.delete_all_cookies()
            self.driver.get('chrome://settings/clearBrowserData')
            time.sleep(5)
            button = self.driver.execute_script("return document.querySelector('settings-ui').shadowRoot.querySelector('settings-main').shadowRoot.querySelector('settings-basic-page').shadowRoot.querySelector('settings-section > settings-privacy-page').shadowRoot.querySelector('settings-clear-browsing-data-dialog').shadowRoot.querySelector('#clearBrowsingDataDialog').querySelector('#clearBrowsingDataConfirm')")
            button.click()
            #self.WebDir(By.XPATH, '//*[@id="clearBrowsingData"]',10)
            #self.driver.find_element_by_xpath('//*[@id="label"]').click()
            #self.WebDir(By.XPATH, '//*[@id="clearBrowsingDataConfirm"]',10)
            #self.driver.find_element_by_xpath('//*[@id="clearBrowsingDataConfirm"]').click()
            self.logsing.emit("线程id " + self.mid + " 清除缓存")

    def login(self,callable,userid,user,password,newpassword):
        #self.url = 'https://cas.baidu.com/?tpl=www2'
        #if callable:
        self.driver.get('https://cas.baidu.com/?tpl=www2')
        self.logsing.emit("线程id " + self.mid + " 用户 " + user + " 打开网站")
        
        self.WebDir(By.XPATH, '//*[@id="uc-login"]/div[1]/div[1]',60)
        #textlogon = self.driver.find_element_by_xpath('//*[@id="app"]/div[1]/div[2]/div[2]/div[1]/span').text
        #if textlogon == "账号登录":
        #    self.driver.find_element_by_xpath('//*[@id="app"]/div[1]/div[2]/div[2]/div[1]/span').click()
        #    time.sleep(0.5)
        #self.WebDir(By.XPATH,'//*[@id="uc-common-account"]',30)
        self.driver.find_element_by_xpath('//*[@id="uc-common-account"]').send_keys(user)
        #self.logsing.emit("线程id " + self.mid + " 用户 " + user + " 输入账号")
        self.driver.find_element_by_xpath('//*[@id="ucsl-password-edit"]').send_keys(password)
        #self.logsing.emit("线程id " + self.mid + " 用户 " + user + " 输入密码")
        self.driver.find_element_by_xpath('//*[@id="submit-form"]').click()
        self.logsing.emit("线程id " + self.mid + " 用户 " + user + " 登录")

        def tongying(m):
            xpath1 = '/html/body/div[{}]/div/div[2]/div/div[2]/div[2]/label/span[1]/input'.format(m)
            xpath2 = '/html/body/div[{}]/div/div[2]/div/div[2]/div[3]/button/span'.format(m)
            try:
                self.driver.find_element_by_xpath(xpath1).click()
                time.sleep(1)
                self.driver.find_element_by_xpath(xpath2).click()
                return True
            except NoSuchElementException as e:
                self.logsing.emit("线程id " + self.mid + " 用户 " + user + str(e.args))
                time.sleep(1)
                if m == 3:
                    return False
                return tongying(3)
            except Exception as e:
                #logeer(str(e),s=True)
                self.logsing.emit("线程id " + self.mid + " 用户 " + user + " " + str(e.args))
                return False

        returns = 0
        while True:
            if self.WebDir(By.XPATH, '//*[text()="百度推广政策简报公告"]',1):
                self.logsing.emit("线程id " + self.mid + " 用户 " + user + " 百度推广政策简报公告")
                tongying(4)
            elif self.WebDir(By.XPATH, '//*[text()="APP应用下载页内容合规协议"]',1):
                self.logsing.emit("线程id " + self.mid + " 用户 " + user + " APP应用下载页内容合规协议")
                tongying(4)
            elif self.WebDir(By.XPATH, '//*[text()="账户中心"]',1):
                time.sleep(3)
                if self.WebDir(By.XPATH, '//*[text()="百度推广政策简报公告"]',2):
                    self.logsing.emit("线程id " + self.mid + " 用户 " + user + " 百度推广政策简报公告")
                    tongying(4)
                elif self.WebDir(By.XPATH, '//*[text()="APP应用下载页内容合规协议"]',2):
                    self.logsing.emit("线程id " + self.mid + " 用户 " + user + " APP应用下载页内容合规协议")
                    tongying(4)
                else:
                    if not self.category:
                        self.myquit(False)
                        return None
                    elif callable:
                        self.logsing.emit("线程id " + self.mid + " 用户 " + user + " 账户中心")
                        return self.setpassword(userid,user,password,newpassword)
                    else:
                        self.myquit(False)
                        return None
            elif self.WebDir(By.XPATH,'//*[text()="修改密码"]',1):
                self.logsing.emit("线程id " + self.mid + " 用户 " + user + " 修改密码")
                return self.netpassword(userid,user,password,newpassword)
            elif self.WebDir(By.XPATH,'//*[@id="token-img"]',1):
                self.logsing.emit("线程id " + self.mid + " 用户 " + user + " 验证码")
                self.driver.maximize_window() # 窗口最大化准备截图

                self.driver.find_element_by_xpath('//*[@id="token-img"]').click()
                time.sleep(0.5)
                if setting.validation == "baidu":
                    pngname = fateadm_api.baiduapi(self.image_str('#token-img'))
                else:
                    pngname = fateadm_api.TestFunc(self.image_str('#token-img'))
                self.logsing.emit("线程id " + self.mid + " 用户 " + user + " 验证码识别结果 " + pngname)
                self.driver.find_element_by_id("uc-common-token").send_keys(pngname)
                self.driver.find_element_by_id("submit-form").click()
            elif self.WebDir(By.XPATH,'//*[text()="拖动滑块，使图片角度为正"]',1):
                # //*[@id="vcode-close479"]
                self.logsing.emit("线程id " + self.mid + " 用户 " + user + " 旋转滑块")
                if setting.rotating == "1":

                    returns += 1
                    if returns > 12:
                        self.logsing.emit("线程id " + self.mid + " 用户 " + user + " 旋转滑块旋转失败")
                        self.myquit(False)
                        return "旋转滑块旋转失败"
                    
                    self.driver.maximize_window() # 窗口最大化准备截图
                    time.sleep(0.5)
                    pngname = self.image_str('.vcode-spin-img')
                    #img_url = self.driver.find_element_by_xpath('//*[@class="vcode-spin-img"]').get_attribute("src")
                    getcmd = subprocess_cmd("correct_rotation.exe {}".format(pngname))
                    getcmd = re.sub("[\n\r]","",getcmd)
                    movex = int(int(getcmd)/360*210)
                    self.logsing.emit("线程id " + self.mid + " 用户 " + user + " 旋转长度 " + str(movex))
                    elenment = self.driver.find_element_by_xpath('//*[@class="vcode-spin-button"]/p')
                    ActionChains(self.driver).move_to_element(elenment).perform()
                    drawing = ActionChains(self.driver).click_and_hold(elenment).move_by_offset(movex, 0).release()
                    drawing.perform()
                
                #'//*[@class="vcode-spin-img"]'
            elif self.WebDir(By.XPATH,'//*[text()="用户名密码错误"]',1):
                self.logsing.emit("线程id " + self.mid + " 用户 " + user + " 用户名密码错误")
                #self.driver.find_element_by_xpath('//*[@id="submit-form"]').click()
                return "登录失败(用户名密码错误)"
            else:
                self.driver.execute_script('javascript:void(0);')
                self.logsing.emit("线程id " + self.mid + " 用户 " + user + " 暂找不到页面")
                returns += 1
                if returns > 8:
                    self.logsing.emit("线程id " + self.mid + " 用户 " + user + " 登录失败,即将进行下一个账号")
                    self.myquit(False)
                    return "登录失败(未识别到页面)"

    def netpassword(self,userid,user,password,newpassword):
        self.driver.find_element_by_xpath('//*[@id="OldPassword"]').send_keys(password)
        self.driver.find_element_by_xpath('//*[@id="NewPassword"]').send_keys(newpassword)
        self.driver.find_element_by_xpath('//*[@id="ReNewPassword"]').send_keys(newpassword)
        self.driver.find_element_by_xpath('//*[@id="Main"]/div[6]/input').click()
        self.logsing.emit("线程id " + self.mid + " 用户 " + user + "修改密码")
        if self.WebDir(By.XPATH,'//*[text()="重新登陆！"]',60):
            self.logsing.emit("线程id " + self.mid + " 用户 " + user + "修改密码成功")
            self.driver.find_element_by_xpath('/html/body/div[1]/div[2]/table/tbody/tr/td/table/tbody/tr/td[1]/a').click()
            if self.WebDir(By.XPATH, '//*[@id="app"]/div[1]/div[2]/div[2]/div[1]/span',60):
                self.login(False,user,password,newpassword)
                self.Binduser(userid,user)
            else:
                self.logsing.emit("线程id " + self.mid + " 用户 " + user + "未重新登录获取绑定")
                self.worksing.emit({"type":"burek","id":userid, "msg":"未重新登录获取绑定"})
            self.myquit(False)
            return None
        else:
            self.logsing.emit("线程id " + self.mid + " 用户 " + user + "修改密码失败")
            self.myquit(False)
            return "修改密码失败"


    def Binduser(self,userid,user):
        self.driver.find_element_by_xpath('//*[text()="账户中心"]').click()
        self.logsing.emit("线程id " + self.mid + " 用户 " + user + " 点击账户中心")
        handl=self.driver.window_handles
        self.driver.switch_to.window(handl[-1])
        self.WebDir(By.XPATH, '//*[text()="账户管理"]',60)
        self.logsing.emit("线程id " + self.mid + " 用户 " + user + " 账户管理")
        if self.WebDir(By.XPATH,'//*[@id="binding-abstract-mcc"]/div[1]/em/a',30):
            txt = self.driver.find_element_by_xpath('//*[@id="binding-abstract-mcc"]/div[1]/em/a').text
            if txt == "1":
                self.driver.find_element_by_xpath('//*[@id="binding-abstract-mcc"]/div[1]/em/a').click()
                self.WebDir(By.XPATH, '//*[text()="处理请求"]',60)
                self.logsing.emit("线程id " + self.mid + " 用户 " + user + " 处理请求")
                self.driver.find_element_by_xpath('//*[text()="处理请求"]').click()
                self.WebDir(By.XPATH, '//*[text()="重要提醒："]',60)
                self.logsing.emit("线程id " + self.mid + " 用户 " + user + " 重要提醒")
                self.driver.find_element_by_xpath('//*[@id="binding-mcc-agreecheckbox"]').click()
                time.sleep(0.5)
                self.WebDir(By.XPATH, '//*[text()="同意绑定"]',60)
                self.driver.find_element_by_xpath('//*[text()="同意绑定"]').click()
                self.logsing.emit("线程id " + self.mid + " 用户 " + user + " 同意绑定")
                self.WebDir(By.XPATH, '//*[text()="您已成功处理该绑定请求"]',60)
                self.driver.find_element_by_xpath('//*[text()="确定"]').click()
                self.logsing.emit("线程id " + self.mid + " 用户 " + user + "已成功处理该绑定请求")
                time.sleep(0.5)
            else:
                self.logsing.emit("线程id " + self.mid + " 用户 " + user + "无绑定信息")
                self.worksing.emit({"type":"burek","id":userid,"msg":"无绑定信息"})
        else:
            self.logsing.emit("线程id " + self.mid + " 用户 " + user + "未获取到绑定信息")
            self.worksing.emit({"type":"burek","id":userid,"msg":"未获取到绑定信息"})

    def setpassword(self,userid,user,password,newpassword):
        self.Binduser(userid,user)
        elenment = self.driver.find_element_by_xpath('//*[text()="账户管理"]')
        ActionChains(self.driver).move_to_element(elenment).perform()
        self.update_action('//*[text()="安全中心"]',elenment)
        self.logsing.emit("线程id " + self.mid + " 用户 " + user + " 打开安全中心")
        handl=self.driver.window_handles
        self.driver.switch_to.window(handl[-1])
        self.WebDir(By.XPATH, '//*[text()="管理密码"]',60)
        elenment = self.driver.find_element_by_xpath('//*[text()="找回、修改密码从这里开始"]')
        ActionChains(self.driver).move_to_element(elenment).perform()
        self.update_action('//*[text()="修改密码"]',elenment)
        self.logsing.emit("线程id " + self.mid + " 用户 " + user + " 打开修改密码页面")
        handl=self.driver.window_handles
        self.driver.switch_to.window(handl[-1])
        self.WebDir(By.XPATH, '//*[text()="登录密码修改"]',60)
        self.driver.find_element_by_xpath('//*[text()="登录密码修改"]').click()
        self.logsing.emit("线程id " + self.mid + " 用户 " + user + "登录密码修改")
        self.driver.find_element_by_xpath('//*[@id="old-password"]').send_keys(password)
        self.driver.find_element_by_xpath('//*[@id="new-password"]').send_keys(newpassword)
        self.driver.find_element_by_xpath('//*[@id="second-new-password"]').send_keys(newpassword)
        self.driver.find_element_by_xpath('//*[@id="modify-password-button"]').click()
        self.logsing.emit("线程id " + self.mid + " 用户 " + user + " 修改密码")
        if self.WebDir(By.XPATH,'//*[text()="安全等级"]',60):
            self.logsing.emit("线程id " + self.mid + " 用户 " + user + "修改成功")
            self.myquit(False)
            return None
        else:
            self.logsing.emit("线程id " + self.mid + " 用户 " + user + "修改失败")
            self.myquit(False)
            return "修改失败"


async def chrome_init_(logsing,worksing):
    pidchr = getpid("chrome.exe",True)
    if pidchr:
        logsing.emit("chrome浏览器运行中")
        version = getversion(pidchr)
        if not version:
            logsing.emit("初始化失败 未检查到浏览器版本 请重试")
        else:
            logsing.emit("chrome版本为: " + version.replace("\n","") + " 即将下载对应驱动")
            ret = getchrdir(logsing,version.replace("\n",""))
            if ret:
                logsing.emit("驱动下载完毕 初始化完成")
            else:
                logsing.emit("初始化失败 驱动下载失败 请重试")
    else:
        logsing.emit("没有运行chrome浏览器 请先运行chrome浏览器")
    worksing.emit({"type":"init"})


def subprocess_cmd(cmd):
    try:
        p = subprocess.Popen(cmd,shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        msg = ''
        for line in p.stdout.readlines():
            msg += line.decode("gbk","ignore")
        p.wait()
        return msg
    except:
        return ""


def getpid(name,nus):
    pid_list = psutil.pids()
    for pid in pid_list:
        try:
            exe_path = psutil.Process(pid).cmdline()[0]
            if os.path.basename(exe_path) == name:
                if nus:
                    setting.set_cfg("db", "chrome_path", os.path.abspath(exe_path))
                    setting.chrome_path = os.path.abspath(exe_path)
                    return os.path.dirname(exe_path)
                os.system('taskkill /pid ' + str(pid) + '  -t  -f')
        except:
            pass
    return None


def getversion(file_path):
    vis = None
    path_list = os.listdir(os.path.abspath(file_path))
    vi_path = os.path.join(file_path,path_list[0])
    path_list = os.listdir(vi_path)
    for file in path_list:
        if file[-8:] == "manifest":
            vis = os.path.join(vi_path,file)
            break
    if vis:
        with open(vis,'r') as file_:
            file_txt = file_.readlines()
        for txt in file_txt:
            vesplit = txt.replace(" ","").split("=")
            if vesplit[0] == 'version':
                return vesplit[1]
    else:
        return vis


def getchrdir(logsing,viver):
    url = "https://npm.taobao.org/mirrors/chromedriver"
    ret = requests.get(url)
    if ret.status_code == 200:
        list_ver = re.compile(r'\d\d.\d.\d\d\d\d.\d+').findall(ret.text)
        if viver in list_ver:
            vivers = viver
        else:
            for ver in list_ver:
                if re.search("(\d+)",viver).group(0) == re.search("(\d+)",ver).group(0):
                    vivers = ver
                    break
            else:
                logsing.emit("镜像未找到对应版本的驱动")
                return False
        res = requests.get(url + "/" + vivers + "/chromedriver_win32.zip")
        if res.status_code == 200 and res.content:
            with open(os.path.join(setting.mypath,vivers + "cher.zip"),"wb") as b:
                b.write(res.content)
            zip_file = zipfile.ZipFile(os.path.join(setting.mypath, vivers + "cher.zip"),mode='r',compression=zipfile.ZIP_DEFLATED)
            zip_file.extractall(vivers)
            zip_file.close()
            os.remove(vivers + "cher.zip")
            setting.set_cfg("db", "chromedriver", os.path.join(setting.mypath,vivers,"chromedriver.exe"))
            setting.chromedriver = os.path.join(setting.mypath,vivers,"chromedriver.exe")
            return True
        else:
            logsing.emit("驱动下载状态码错误")
            return False
    else:
        logsing.emit("镜像访问失败")
        return False
